using System;
using System.Collections.Generic;
using System.Text;

using System.IO;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;
using System.Net;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels;
using RemoteObject;

namespace RemoteClient
{
    public class MyClient
    {
        static Dictionary<long, DownloadJob> cloudFileDictionary = new Dictionary<long, DownloadJob>();

        public static string LocalIPAddress = Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString();
        static string RemoteServerUrl = "ServiceURLTcp";
        public static string CloudServerURL = System.Configuration.ConfigurationManager.AppSettings[RemoteServerUrl];
        
        [Serializable]
        public class BlockInfo
        {
            public int blockID, originPos, currentPos, remainDataLength;

        }

        public enum Status
        {
            Working,
            Pause,
            Completed
        }

        //debug use only
        static void PrintProgress(BlockInfo blockinfo)
        {
            double finishedLength = blockinfo.currentPos - blockinfo.originPos;
            double totalLength = blockinfo.remainDataLength + finishedLength;
            double result = finishedLength / totalLength * 100;
            //Console.WriteLine("Block [" + blockinfo.blockID + "] --- " + result.ToString("f1") + " %");
            if (result == 100) Console.WriteLine("Block [" + blockinfo.blockID + "] --- Completed");
        }
        //debug use only


        [STAThread]
        static void Main(string[] args)
        {
            StartServer();
            System.Windows.Forms.Application.Run(new UI.ClientForm());
            
        }

        static void StartServer()
        {
            IPHostEntry IpEntry = Dns.GetHostEntry(Dns.GetHostName());
            string IPAddress = IpEntry.AddressList[0].ToString();

            Console.Write("Is this cloud server?[y|n] ");
            String answer = Console.ReadLine().ToString();
            if (answer == "y")
            {
                Common.CloudServerURL = String.Format("tcp://{0}:10001/RemoteObject.RemoteObjectDownloader", IPAddress);
            }
            else
            {
                //Console.Write("Please define the cloud server ip ");
                //String ip = Console.ReadLine().ToString();
                //Common.CloudServerURL = String.Format("tcp://{0}:10001/RemoteObject.RemoteObjectDownloader", ip);
            }


            // **********LOCAL SERVER STARTUP********** //
            TcpChannel chanTcp = new TcpChannel(/*tcpPort*/ 10001);
            //HttpChannel chanHttp = new HttpChannel(/*httpPort*/ 10002);       

            ChannelServices.RegisterChannel(chanTcp, false);
            //ChannelServices.RegisterChannel(chanHttp, false);     
            Console.WriteLine("The name of the TCPChannel is {0}.",
                chanTcp.ChannelName);
            Console.WriteLine("The priority of the TCPChannel is {0}.",
                chanTcp.ChannelPriority);
            Console.WriteLine("The name of the HttpChannel is {0}.",
                chanTcp.ChannelName);
            Console.WriteLine("The priority of the HttpChannel is {0}.",
                chanTcp.ChannelPriority);
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemoteObject.RemoteObjectDownloader), "RemoteObject.RemoteObjectDownloader", WellKnownObjectMode.Singleton);
            RemoteObject.RemoteObjectDownloader.OnUploadRequest += new RemoteObject.RemoteObjectDownloader.MessageHandler(Request_OnUploadRequest);
            RemoteObject.RemoteObjectDownloader.OnDistributeRequest += new RemoteObject.RemoteObjectDownloader.MessageHandler(Request_OnDistributeRequest);
            RemoteObject.RemoteObjectDownloader.OnStopUploadRequest += new RemoteObject.RemoteObjectDownloader.MessageHandler2(Request_OnStopUploadRequest);
            RemoteObject.RemoteObjectDownloader.OnSyncRequest += new RemoteObject.RemoteObjectDownloader.MessageHandler3(Request_OnSyncRequest);
            RemoteObject.RemoteObjectDownloader.OnJobDistributionRequest += new RemoteObject.RemoteObjectDownloader.MessageHandler4(Request_OnJobListRequest);
            // **********LOCAL SERVER STARTUP********** //
        }

        public static void Request_OnUploadRequest(string fnRemote, string fnLocal, string ip, long jobID) //
        {
            //init downloader on host
            DownloadJob downloadJob = new DownloadJob(fnLocal, fnRemote, String.Format("tcp://{0}:10001/RemoteObject.RemoteObjectDownloader", ip));
            cloudFileDictionary.Add(jobID, downloadJob);
            Thread thread = new Thread(new ThreadStart(downloadJob.Start));
            thread.Start();
            Thread.Sleep(100);
        }

        public static void Request_OnDistributeRequest(string fnRemote, string fnLocal, string ip, long jobID)
        {
            DownloadJob downloadJob = new DownloadJob(fnLocal, fnRemote, String.Format("tcp://{0}:10001/RemoteObject.RemoteObjectDownloader", ip));
            cloudFileDictionary.Add(jobID, downloadJob);
        }

        public static void Request_OnStopUploadRequest(long jobID)
        {
            DownloadJob job = ((DownloadJob)cloudFileDictionary[jobID]);
            job.Cancel();
        }

        public static RemoteObject.JobInfo Request_OnSyncRequest(long jobID)
        {
            DownloadJob job = ((DownloadJob)cloudFileDictionary[jobID]);
            RemoteObject.JobInfo jobInfo = new RemoteObject.JobInfo();
            jobInfo.progress = job.GetProgress();
            jobInfo.transferSpeed = job.GetTransferSpeed();
            return jobInfo;
        }

        public static List<DownloadJobTicket> Request_OnJobListRequest()
        {
            List<DownloadJob> jobList = new List<DownloadJob>(cloudFileDictionary.Values);
            List<DownloadJobTicket> ticketList = new List<DownloadJobTicket>();
            foreach (DownloadJob job in jobList)
            {
                ticketList.Add(job.GetDownloadJobTicket());
            }
            jobList.Clear();
            jobList = null;
            return ticketList;
        }

    }
}
